package com.kaochong.xcx.service.impl;

import com.google.common.collect.Lists;

import com.kaochong.common.util.BeanConvertUtil;
import com.kaochong.xcx.cache.TokenCache;
import com.kaochong.xcx.cache.UserInfoCache;
import com.kaochong.xcx.cache.UserMistakesCache;
import com.kaochong.xcx.cache.UserWordCache;
import com.kaochong.xcx.cache.WordCache;
import com.kaochong.xcx.dao.UserStageWordsMapper;
import com.kaochong.xcx.entity.UserInfo;
import com.kaochong.xcx.entity.UserMistakes;
import com.kaochong.xcx.entity.UserStageWords;
import com.kaochong.xcx.entity.WordBook;
import com.kaochong.xcx.enums.FinishStatus;
import com.kaochong.xcx.enums.StageStatus;
import com.kaochong.xcx.pojo.cache.WordModel;
import com.kaochong.xcx.pojo.vo.LearnWordVO;
import com.kaochong.xcx.service.UserInfoService;
import com.kaochong.xcx.service.UserMistakesService;
import com.kaochong.xcx.service.UserStageWordsService;
import com.kaochong.xcx.service.WordBookService;
import com.kaochong.xcx.utils.CalculateUtil;
import com.kaochong.xcx.utils.DateUtil;
import com.kaochong.xcx.utils.JsonUtil;
import com.kaochong.xcx.utils.MixUtil;
import com.kaochong.xcx.web.aspect.CurrentUser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;

/**
 * @author han
 * @date 2018-05-02 16:37
 */
@Service
@Slf4j
public class UserStageWordsServiceImpl implements UserStageWordsService {
	
	@Autowired
	UserStageWordsMapper userStageWordsMapper;
	
	@Autowired
	WordCache wordCache;
	
	@Autowired
	UserWordCache userWordCache;
	
	@Autowired
	UserMistakesService userMistakesService;
	
	/*@Autowired
	UserInfoRepository userInfoRepository;*/
	UserInfoService userInfoService;
	
	@Autowired
	TokenCache tokenCache;
	
	@Autowired
	UserInfoCache userInfoCache;
	
	@Autowired
	UserMistakesCache userMistakesCache;
	
	@Autowired
	MixUtil mixUtil;
	
	@Autowired
	WordBookService wordBookService;
	
	/**
	 * 重置后默认为第一阶段
	 */
	private final static Integer DEFAULT_STAGE = 1;
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void reset(Long userId, Integer target, String targetMarkId) {
		
		// 1、获取第一阶段题库的题
		List<WordModel> stageList = wordCache.getStageWord(target, DEFAULT_STAGE);
		
		Map<String, Object> map = mixUtil.mixUp(stageList, target);
		
		List<WordModel> wordList = (List<WordModel>) map.get("wordList");
		List<Integer> ids = (List<Integer>) map.get("ids");
				
		// 4、存数据库
		UserStageWords stageWords = new UserStageWords();
		stageWords.setUserId(userId);
		stageWords.setTargetMarkId(targetMarkId);
		stageWords.setStage(DEFAULT_STAGE);
		stageWords.setFinishStatus(StageStatus.DEFAULT.getCode());
		stageWords.setWordIds(JsonUtil.toJson(ids));
		stageWords.setCreateTime(new Date());
		stageWords.setUpdateTime(new Date());
		userStageWordsMapper.insert(stageWords);
		
		// 5、存redis
		userWordCache.set(userId, DEFAULT_STAGE, targetMarkId, wordList);
		String key = userInfoCache.genKey(userId, targetMarkId, DEFAULT_STAGE);
		userInfoCache.hPutTodayUserInfo(key, wordList.size(), 0);
	}
	
	@Override
	public UserStageWords findUserStageWord(Long userId, String targetMarkId, Integer stage) {
		UserStageWords userStageWords = userStageWordsMapper
				.findUserStageWord(userId, targetMarkId, stage);
		return userStageWords;
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public List<WordModel> getUserStageWord(CurrentUser userInfo) {
		Long userId = userInfo.getId();
		Integer target = userInfo.getTarget();
		Integer currStage = userInfo.getCurrStage();
		String targetMarkId = userInfo.getTargetMarkId();
		
		WordBook wordBook = wordBookService.getWordBook(target);
		Integer totalStage = wordBook.getTotalStage();
		int reviewBegin = totalStage - wordBook.getReview();
		
		// redis中获取
		List<WordModel> wordList = userWordCache.get(userId, currStage, targetMarkId);
		if (currStage > totalStage) {
			UserInfo one = userInfoService.selectById(targetMarkId);
			String testResult = one.getTestResult();
			if (null == testResult) {
				testResult = "0/100";
			}
			String test = testResult.substring(0, testResult.indexOf("/"));
			String key = userInfoCache.genKey(userId, targetMarkId, totalStage);
			if (!userInfoCache.exit(key, "finalTest")) {
				userInfoCache.hPutTodayUserInfo(key, 100, userInfo.getStudyWordsNum(), test);
			}
			return Lists.newArrayList();
		}
		if (null == wordList || wordList.isEmpty()) {
			List<WordModel> stageList = new ArrayList<>();
			// 学习阶段获取每阶段对应的题库
			if (currStage <= reviewBegin) {
				// 当前阶段固定的50个单词
				stageList = wordCache.getStageWord(target, currStage);
			} else {
			// 复习阶段查询错误等于三次的错题
				// TODO 该为动态添加单词书之前
//				stageList = getReview(target, userId, currStage, targetMarkId);
				stageList = getNewReview(wordBook, userId, currStage, targetMarkId);
			}
			
			if (currStage < totalStage) {
				// 前一/两阶段错误的单词
				List<UserMistakes> mistakes =
						userMistakesService.findBeforeTwoDayMistakes(userId, targetMarkId, 0, currStage, 2, target);
				
				if (!mistakes.isEmpty()) {
					// 错题id查询问题
					List<Integer> ids = new ArrayList<>();
					for (UserMistakes mistake : mistakes) {
						ids.add(mistake.getWordId());
					}
					// redis查之前错的题
					List<WordModel> errorList = wordCache.getTypeWordByIds(target, ids);
					
					// 合并两个list
					stageList.addAll(errorList);
				}
			}
			
			Map<String, Object> map = mixUtil.mixUp(stageList, target);
			
			wordList = (List<WordModel>) map.get("wordList");
			List<Integer> stageIds = (List<Integer>) map.get("ids");
			
			Integer finishStatus = FinishStatus.DEFAULT.getCode();
			
			if (stageIds.size() == 0) {
				finishStatus = FinishStatus.FINISHED.getCode();
			}
			
			Date now = new Date();
			
			UserStageWords userStageWords = findUserStageWord(userId, targetMarkId, currStage);
			if (userStageWords == null) {
				UserStageWords stageWords = new UserStageWords();
				stageWords.setUserId(userId);
				stageWords.setTargetMarkId(targetMarkId);
				stageWords.setStage(currStage);
				stageWords.setFinishStatus(finishStatus);
				stageWords.setWordIds(JsonUtil.toJson(stageIds));
				stageWords.setCreateTime(now);
				stageWords.setUpdateTime(now);
				userStageWordsMapper.insert(stageWords);
			} else {
				userStageWords.setWordIds(JsonUtil.toJson(stageIds));
				userStageWords.setUpdateTime(now);
				userStageWordsMapper.updateByPrimaryKey(userStageWords);
			}
			
			// 修改用户当前阶段状态
			UserInfo one = userInfoService.selectById(targetMarkId);
			int diffDay = DateUtil.daysBetween(one.getLastStudyTime(), now);
			if(diffDay > 1) {
				if (StageStatus.FINISHED.getCode().equals(finishStatus)){
					one.setKeepDay(1);
					one.setLastStudyTime(now);
					userInfo.setKeepDay(1);
				} else {
					one.setKeepDay(0);
					userInfo.setKeepDay(0);
				}
			} else {
				if (StageStatus.FINISHED.getCode().equals(finishStatus)){
					if (one.getCurrStage().equals(currStage) && one.getCurrStageStatus().equals(StageStatus.FINISHED.getCode())) {
						log.info("【我不可能被执行————————————————————————————————————————】");
					} else {
						int keepDay = one.getKeepDay() + 1;
						one.setKeepDay(keepDay);
						one.setLastStudyTime(now);
						userInfo.setKeepDay(keepDay);
					}
				}
			}
			one.setCurrStage(currStage);
			one.setCurrStageStatus(finishStatus);
			one.setUpdateTime(now);
			userInfoService.update(one);
			
			userInfo.setLastStudyTime(now);
			userInfo.setCurrStageStatus(finishStatus);
			
			String key = userInfoCache.genKey(userId, targetMarkId, currStage);
			userInfoCache.hPutTodayUserInfo(key, wordList.size(), userInfo.getStudyWordsNum());
			tokenCache.setToken(userInfo.getToken(), userInfo);
			
			// 存入redis
			userWordCache.set(userId, currStage, targetMarkId, wordList);
		}
		return wordList;
	}
	
	private List<WordModel> getNewReview(WordBook wordBook, Long userId, Integer currStage, String
			targetMarkId) {
		Integer target = wordBook.getTarget();
		List<WordModel> stageList = Lists.newArrayList();
		
		List<UserMistakes> finalReviewMistakes = userMistakesService.findUserReviewMistakes(userId, targetMarkId, 0, 3, target);
		
		Integer percent = 0;
		List<Integer> ids = Lists.newArrayList();
		
		// 判断获取的是复习阶段
		if (currStage <= wordBook.getMaxStudyStage() || currStage > wordBook.getTotalStage()) {
			return stageList;
		}
		
		String reviewDetail = wordBook.getReviewDetail();
		Map map = JsonUtil.toObject(reviewDetail, Map.class);
		if (null == map || map.isEmpty()) {
			return stageList;
		}
		
		percent = (Integer) map.get(currStage) == null ? 0 : (Integer) map.get(currStage);
		if (currStage >= wordBook.getTotalStage()) {
			// 查询所有错题
			finalReviewMistakes = userMistakesService.findAllMistakes(userId, targetMarkId, target);
			for (UserMistakes finalReviewMistake : finalReviewMistakes) {
				ids.add(finalReviewMistake.getWordId());
			}
			stageList = wordCache.getTypeWordByIds(target, ids);
			stageList = getFinalTest(stageList, target);
		} else {
			Integer num = CalculateUtil.calcPercent(percent, finalReviewMistakes.size());
			if (num > 0) {
				finalReviewMistakes = finalReviewMistakes.subList(0, num);
				for (UserMistakes finalReviewMistake : finalReviewMistakes) {
					ids.add(finalReviewMistake.getWordId());
				}
				stageList = wordCache.getTypeWordByIds(target, ids);
			}
		}
		return stageList;
	}
	
	@Override
	public List<LearnWordVO> learnList(CurrentUser user, Integer stage) {
		List<LearnWordVO> listVO = Lists.newArrayList();
		
		Integer target = user.getTarget();
		Long userId = user.getId();
		String mark = user.getTargetMarkId();
		Integer currStage = user.getCurrStage();
		Integer currStageStatus = user.getCurrStageStatus();
		
		WordBook wordBook = wordBookService.getWordBook(target);
		Integer maxStudyStage = wordBook.getTotalStage() - wordBook.getReview();
		
		if (stage > currStage) {
			stage = currStage;
		}
		
		if (stage > maxStudyStage) {
			stage = maxStudyStage;
		} else {
			if (currStage == stage && !StageStatus.FINISHED.getCode().equals(currStageStatus)) {
				stage = stage - 1 == 0 ? 0 : stage - 1;
			}
		}
		List<WordModel> stageWord = wordCache.getStageWord(target, stage);
		List<UserMistakes> mistakes = userMistakesCache.hGetAll(userId, mark);
		if (mistakes.isEmpty()) {
			mistakes = userMistakesService.findAllMistakes(userId, mark, target);
		}
		
		listVO = BeanConvertUtil.convert(stageWord, LearnWordVO.class);
		
		for (UserMistakes mistake : mistakes) {
			for (LearnWordVO vo : listVO) {
				if (mistake.getWordId().equals(vo.getId())) {
					vo.setRightSign(false);
					break;
				}
			}
		}
		return listVO;
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Integer deleteUserStage(Long userId, String targetMarkId) {
		return userStageWordsMapper.deleteUserStage(userId, targetMarkId);
	}
	
//	private final static Integer total = 500;
//	private final static Integer final_test_total = 100;
//	private final static Integer final_test_error_base = 80;
//	private final static Integer final_test_right_base = 20;
	
	private List<WordModel> getFinalTest(List<WordModel> mistakesList, Integer target) {
		WordBook wordBook = wordBookService.getWordBook(target);
		Integer total = wordBook.getWordsNum();
		Integer final_test_total = wordBook.getFinalTestTotal();
		Integer final_test_error_base = wordBook.getFinalTestErrorNum();
		Integer final_test_right_base = wordBook.getFinalTestRightNum();
		
		Integer right;
		
		// 查所有
		List<WordModel> allWord = wordCache.getAllTypeWord(target);
		
		List<WordModel> rightList = Lists.newArrayList();
		
		// 打乱顺序
		Collections.shuffle(allWord);
		Collections.shuffle(mistakesList);
		
		
		Set<Integer> idsSet = new HashSet<>();
		for (WordModel wordModel : mistakesList) {
			idsSet.add(wordModel.getId());
		}
		
		// 错误数小于80
		// 取出所有 填补正确的 凑够100题
		if (idsSet.size() <= final_test_error_base) {
			// 需要取的正确题目数
			right = final_test_total - mistakesList.size();
		} else if (idsSet.size() <= (total - final_test_right_base)){
			// 打乱所有错题 取80题
			mistakesList = mistakesList.subList(0, final_test_error_base);
			right = final_test_right_base;
		} else {
			// 取不足30题的正确题目
			right = total - mistakesList.size();
			
			// 取100-right的错误题目
			mistakesList = mistakesList.subList(0, idsSet.size()-right);
		}
		
		Integer id;
		for (int i = 0; i < allWord.size(); i++) {
			if (right == 0) {
				break;
			}
			id = allWord.get(i).getId();
			if (!idsSet.contains(id)) {
				idsSet.add(id);
				rightList.add(allWord.get(i));
				right --;
			}
		}
		// 和错题混在一起
		mistakesList.addAll(rightList);
		return mistakesList;
	}
}